pub mod rpc_server {
    tonic::include_proto!("config_monitor_s");
}
use std::{collections::HashMap, sync::Arc};

use tonic::{Request, Response, Status};

use crate::agent::{rpc_client, Agent};

/// rpc调用绑定在这个结构体上，实现了trait
///
/// Myserver.run()方法中启动了rpc_server，创建了一个impl实例对象，rpc函数中需要操作MyServer的repo和agents字段
///
/// 需要将MyServer的repo和agents字段传入RpcServerimpl中。
pub struct RpcServerimpl {
    /// git仓库在server节点中的路径前缀
    repo_path: String,
    agents: Arc<tokio::sync::Mutex<Box<HashMap<String, Agent>>>>,
}

impl RpcServerimpl {
    pub fn new(
        repo_path: String,
        agents: Arc<tokio::sync::Mutex<Box<HashMap<String, Agent>>>>,
    ) -> Self {
        RpcServerimpl { repo_path, agents }
    }
}

#[tonic::async_trait]
impl rpc_server::config_monitor_s_server::ConfigMonitorS for RpcServerimpl {
    async fn register_agent(
        &self,
        request: Request<rpc_server::RegisterAgentRequest>,
    ) -> Result<Response<rpc_server::RegisterAgentResponse>, Status> {
        println!("*** agent[{}]注册", request.get_ref().agent_address);
        let agent_address = request.get_ref().agent_address.clone();
        let agent = Agent::new(agent_address.clone());

        // 向这个agent初始化文件
        agent.init_files(self.repo_path.clone()).await.unwrap();
        // 将agent加入到agents中
        self.agents.lock().await.insert(agent_address, agent);

        let reply = rpc_server::RegisterAgentResponse {
            success: true,
            message: format!(
                "Agent registered successfully, address: {}",
                request.get_ref().agent_address
            ),
        };
        Ok(Response::new(reply))
    }

    /// agent上报异常
    async fn report_exception(
        &self,
        request: Request<rpc_server::ReportExceptionRequest>,
    ) -> Result<Response<rpc_server::ReportExceptionResponse>, Status> {
        #[cfg(debug_assertions)]
        println!("!!!Got a rpc report_exception request: {:?}", request);

        let agent_address = request.get_ref().agent_address.clone();
        let exception = request.get_ref().exception_message.clone();

        //解析出exception的文件路径 形如key=\"CM_{file_path}，截止到第一个"
        #[cfg(debug_assertions)]
        println!("exception: {}", exception);

        println!("{}", Self::parse_audit_log(&request));

        let file_path = exception
            .split("key=\"CM_")
            .collect::<Vec<&str>>()
            .get(1)
            .unwrap()
            .split("\"")
            .collect::<Vec<&str>>()
            .get(0)
            .unwrap()
            .to_string();

        let reply = rpc_server::ReportExceptionResponse {
            success: true,
            message: format!("Agent {} reported exception: {}", agent_address, exception),
        };

        // sync_config_file
        rpc_client::config_monitor_a_client::ConfigMonitorAClient::connect(
            "http://".to_owned() + &agent_address.clone(),
        )
        .await
        .unwrap()
        .sync_config(tonic::Request::new(rpc_client::SyncConfigRequest {
            config_file_path_agent: file_path.clone(),
            config_file_content: std::fs::read_to_string(self.repo_path.clone() + &file_path)
                .unwrap(),
            action: rpc_client::ConfigFileAction::Sync as i32,
        }))
        .await
        .unwrap();

        Ok(Response::new(reply))
    }
}
impl RpcServerimpl {
    fn parse_audit_log(request: &Request<rpc_server::ReportExceptionRequest>) -> String {
        let exception_message = request.get_ref().exception_message.clone();
        let parts: Vec<&str> = exception_message.split_whitespace().collect();
        let agent = request.get_ref().agent_address.clone();
        let mut key = "";
        let mut comm = "";
        let mut exe = "";
        let mut pid = "";
        let mut user = "";

        for part in parts {
            if part.starts_with("key=") {
                key = part
                    .split("key=\"CM_")
                    .collect::<Vec<&str>>()
                    .get(1)
                    .unwrap()
                    .split("\"")
                    .collect::<Vec<&str>>()
                    .get(0)
                    .unwrap();
            } else if part.starts_with("comm=") {
                comm = part
                    .split("comm=")
                    .collect::<Vec<&str>>()
                    .get(1)
                    .unwrap()
                    .trim_matches('"');
            } else if part.starts_with("exe=") {
                exe = part
                    .split("exe=")
                    .collect::<Vec<&str>>()
                    .get(1)
                    .unwrap()
                    .trim_matches('"');
            } else if part.starts_with("pid=") {
                pid = part.split("pid=").collect::<Vec<&str>>().get(1).unwrap();
            } else if part.starts_with("AUID=") {
                user = part
                    .split("AUID=")
                    .collect::<Vec<&str>>()
                    .get(1)
                    .unwrap()
                    .trim_matches('"');
            }
        }

        format!(
            "!!! 发生了异常的配置文件修改: 主机{}中的配置文件{}被用户{}使用进程{}(可执行文件: {}, Pid: {})进行了修改, 已复原",
            agent,key, user, comm, exe, pid
        )
    }
}
